package com.credithc.customers.api.service.impl;

import com.credithc.baseserv.core.codes.CoreCodes;
import com.credithc.baseserv.core.convert.BaseConverter;
import com.credithc.baseserv.core.message.MessageFactory;
import com.credithc.baseserv.core.utils.UUIDUtils;
import com.credithc.customers.api.service.ICustomerService;
import com.credithc.customers.api.service.IPreCustomerService;
import com.credithc.customers.base.codes.CustomerCodes;
import com.credithc.customers.base.constants.CustomerConstants;
import com.credithc.customers.base.exception.CustomerException;
import com.credithc.customers.base.factory.DictionaryFactory;
import com.credithc.customers.base.mapper.CustomerContactInfoMapper;
import com.credithc.customers.base.po.CustomerContactFlowPo;
import com.credithc.customers.base.po.CustomerContactInfoPo;
import com.credithc.customers.base.ro.*;
import com.credithc.customers.base.service.IBaseCustomerService;
import com.credithc.customers.base.service.ICommonService;
import com.credithc.customers.base.utils.ClassUtils;
import com.credithc.eagleeye.plugins.thread.EagleEyeRunnable;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

import java.sql.Date;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;


/**
 * @Title: 客户开户
 * @Author: Denghx
 * @Date: 2018/11/29 0:04
 * @Description: com.credithc.customers.api.service.impl
 * @Version: V1.0.0
 */
@Service
@Slf4j
public class CustomerServiceImpl implements ICustomerService {
    @Autowired
    private CustomerContactInfoMapper customerContactInfoMapper;
    @Autowired
    private BaseConverter<CustomerContactModifyRo, CustomerContactFlowPo> converterModifyContactRoToPo;
    @Autowired
    private ICommonService commService;
    @Autowired
    private IPreCustomerService preCustomerService;
    @Autowired
    private MessageFactory messageFactory;
    @Autowired
    private IBaseCustomerService baseCustomerService;

    @Override
    public Map<String, String> createCustomerNo(BaseRequest<CustomerInfoRo> request) {
        return baseCustomerService.createCustomerNo(request);
    }

    @Override
    public Map<String, String> updateCustomerNo(BaseRequest<CustomerContactModifyRo> request, String customerNo) {
        log.info("客户信息修改接口开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>入参:{}>>>customerNo：{}", request, customerNo);
        try {
            CustomerContactModifyRo.checkBaseParam(request.getBody());
            Map<String, String> map;
            String prefix = customerNo.substring(0, 1);
            if (CustomerConstants.PRE_CUSTOMER_PREFIX.equals(prefix)
                    || CustomerConstants.IS_CUSTOMER_PREFIX.contains(prefix)) {
                if (CustomerConstants.PRE_CUSTOMER_PREFIX.equals(prefix)) {
                    commService.checkContactModifyParam(request, customerNo, true);
                    map = preCustomerService.updatePreCustomerNo(request, customerNo);
                } else {
                    commService.checkContactModifyParam(request, customerNo, false);
                    map = updateCustomerContact(request, customerNo);
                }
                insertCustomerContactFlow(request, customerNo, CustomerConstants.STATUS_SUCCESS, null);
                return map;
            } else {
                insertCustomerContactFlow(request, customerNo, CustomerConstants.STATUS_FAIL, messageFactory.getInstance(CustomerCodes.PARAM_VALIDATE_ERROR).getMsg());
                throw new CustomerException(CustomerCodes.PARAM_VALIDATE_ERROR);
            }
        } catch (CustomerException e) {
            log.info("客户基本信息修改异常>>>{}", e.getMsg());
            insertCustomerContactFlow(request, customerNo, CustomerConstants.STATUS_FAIL, StringUtils.isNotBlank(e.getMsg()) ? e.getMsg() : messageFactory.getInstance(e.getCode()).getMsg());
            throw new CustomerException(e.getCode(), e.getMsg());
        }
    }


    public Map<String, String> updateCustomerContact(BaseRequest<CustomerContactModifyRo> request, String customerNo) {
        try {
            String systemSign = request.getSystemSign();
            String subSystemSign = request.getSubSystemSign();
            String oldContactType = request.getBody().getContactTypeOld();
            String oldContactInfo = request.getBody().getContactInfoOld();
            String contactType = request.getBody().getContactType();
            String contactInfo = request.getBody().getContactInfo();
            Map<String, String> map = new HashMap<>(3);
            CustomerContactInfoPo po = new CustomerContactInfoPo();
            if (StringUtils.isBlank(oldContactType) || StringUtils.isBlank(oldContactInfo)) {
                po = commService.getExistCustomerContact(systemSign, subSystemSign, customerNo);
            } else {
                po = commService.getExistCustomerContact(systemSign, subSystemSign, oldContactType, oldContactInfo, customerNo);
            }
            CustomerContactInfoPo newPo = commService.getExistCustomerContact(systemSign, subSystemSign, contactType, contactInfo, customerNo);
            po.setContactInfo(contactInfo);
            po.setContactType(contactType);
            po.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            //新联系方式不存在修改当前记录；存在则删除当前记录
            if (newPo == null) {
                customerContactInfoMapper.updateByPrimaryKeySelective(po);
            } else if (contactType.equals(oldContactType) && contactInfo.equals(oldContactInfo)) {
            } else {
                customerContactInfoMapper.deleteByPrimaryKey(po.getId());
            }
            map.put("customerNo", customerNo);
            map.put("contactType", contactType);
            map.put("contactInfo", contactInfo);
            return map;
        } catch (DataAccessException e) {
            log.info("更新联系信息表异常:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
            throw new CustomerException(CustomerCodes.DATABASE_ERROR_UPDATE);
        }
    }

    /**
     * @param customerNo
     * @param status
     * @description: 客户联系信息修改流水
     * @author: denghx
     * @date: 2018/12/2 3:07
     * @param: request
     * @return: void
     */
    private void insertCustomerContactFlow(BaseRequest<CustomerContactModifyRo> request, String customerNo, int status, String errorMessage) {
        try {
            CustomerContactFlowPo flowPo = converterModifyContactRoToPo.convert(request.getBody(), CustomerContactFlowPo.class);
            flowPo.setId(UUIDUtils.getUUID());
            flowPo.setCustomerNo(customerNo);
            flowPo.setModifyType(CustomerConstants.MODIFY_TYPE_CONTACT);
            flowPo.setSystemSign(request.getSystemSign());
            flowPo.setSubSystemSign(request.getSubSystemSign());
            flowPo.setStatus(status);
            flowPo.setCreateTime(new Timestamp(System.currentTimeMillis()));
            flowPo.setCreateDate(new Date(System.currentTimeMillis()));
            if (status == CustomerConstants.STATUS_FAIL) {
                flowPo.setRemark(errorMessage);
            }
            commService.insertContactFlow(flowPo);
        } catch (DataAccessException e) {
            log.info("插入客户联系信息流水异常:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
            throw new CustomerException(CustomerCodes.DATABASE_ERROR_INSERT);
        }
    }

    @Override
    public List<Map<String, Object>> batchCustomerNo(BaseBatchRequest<BatchCustomerRo> request) {
        List<Map<String, Object>> resList = new ArrayList<>();
        String systemSign = request.getSystemSign();
        String subSystemSign = request.getSubSystemSign();
        String signature = request.getSignature();
        Long requestTimestamp = request.getRequestTimestamp();
        List<BatchCustomerRo> ros = request.getBody();
        if (ros.size() > 1000) {
            log.info("============批量条数超过1000条============");
            throw new CustomerException(CustomerCodes.BIZ_VALIDATE_ERROR, "一次批量不允许超过1000条");
        }
        startThread(ros, resList, systemSign, subSystemSign, signature, requestTimestamp);
        log.info("==========线程结束了==========");
        return resList;
    }

    @Override
    public Map<String, String> verifyCustomer(BaseRequest<CustomerIdInfoRo> bRequest) {
        CustomerIdInfoRo ro = bRequest.getBody();
        //目前需配置HSH和HENGYIKA实名认证校验
        Map<String, String> checkRuleDictMap = DictionaryFactory.Dict.IDENTIFY_CHECK_RULE.getDictMap();
        String checkRule = checkRuleDictMap.get(bRequest.getSubSystemSign());
        if (StringUtils.isNotBlank(checkRule) && (CustomerConstants.IDENTIFY_CHECK.equalsIgnoreCase(checkRule))) {
            Map<String, String> map = commService.custIdentity(ro.getIdCardNo(), ro.getCustomerName());
            if (!"2010".equals(map.get("resCode"))) {
                //验证失败
                throw new CustomerException(CustomerCodes.PARAM_VALIDATE_ERROR, "身份验证失败，详细信息为:" + map.get("resMsg"));
            }
        }
        return null;
    }

    private static int threadNumber = 10;

    private void startThread(List<BatchCustomerRo> ros, List<Map<String, Object>> resList,
                             String systemSign, String subSystemSign,
                             String signature, Long requestTimestamp) {
        try {
            int roSize = ros.size();
            if (threadNumber > roSize) {
                threadNumber = roSize;
            }
            int avgNum = roSize / threadNumber;
            int remainderNum = roSize % threadNumber;
            int end = 0;
            final CountDownLatch countDownLatch = new CountDownLatch(threadNumber);
            for (int i = 0; i < threadNumber; i++) {
                int start = end;
                end = start + avgNum;
                if (i == (threadNumber - 1)) {
                    end = roSize;
                } else if (i < remainderNum) {
                    end = end + 1;
                }
                String threadName = "线程Customer[" + (i + 1) + "]";
                /*BThread bThread = new BThread(ros, start, end, countDownLatch, resList, systemSign, subSystemSign, signature, requestTimestamp);
                bThread.setName(threadName);
                bThread.start();*/
                RunThread runThread = new RunThread(ros, start, end, countDownLatch, resList, systemSign, subSystemSign, signature, requestTimestamp);
                Thread thread = new Thread(new EagleEyeRunnable(runThread));
                thread.setName(threadName);
                thread.start();
            }
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    class BThread extends Thread {

        private List<BatchCustomerRo> list;
        private int startIndex;
        private int endIndex;
        private CountDownLatch countDownLatch;
        private List<Map<String, Object>> resList;
        private String systemSign;
        private String subSystemSign;
        private String signature;
        private Long requestTimestamp;

        BThread(List<BatchCustomerRo> ros, int startIndex, int endIndex,
                CountDownLatch countDownLatch, List<Map<String, Object>> resList,
                String systemSign, String subSystemSign,
                String signature, Long requestTimestamp) {
            this.list = ros;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.countDownLatch = countDownLatch;
            this.resList = resList;
            this.systemSign = systemSign;
            this.subSystemSign = subSystemSign;
            this.signature = signature;
            this.requestTimestamp = requestTimestamp;
        }

        @Override
        public void run() {
            List<BatchCustomerRo> subList = list.subList(startIndex, endIndex);
            //TODO 逻辑处理
            for (BatchCustomerRo ro : subList) {
                Map<String, Object> resMap = new HashMap<>(8);
                String dataId = ro.getDataId();
                String requestNo = ro.getRequestNo();
                if (StringUtils.isBlank(dataId)) {
                    resMap.put("dataId", null);
                    resMap.put("requestNo", requestNo);
                    resMap.put("errMsg", "dataId不能为空");
                    resList.add(resMap);
                } else {
                    BaseRequest<CustomerInfoRo> singleRequest = new BaseRequest<>();
                    singleRequest.setRequestTimestamp(requestTimestamp);
                    singleRequest.setSystemSign(systemSign);
                    singleRequest.setSubSystemSign(subSystemSign);
                    singleRequest.setSignature(signature);
                    singleRequest.setBody(ro);
                    try {
                        Map<String, String> singleResMap;
                        singleResMap = baseCustomerService.createCustomerNo(singleRequest);
                        resMap.put("dataId", dataId);
                        resMap.put("customerNo", singleResMap.get("customerNo"));
                    } catch (CustomerException e) {
                        String msg = StringUtils.isNotBlank(e.getMsg()) ? e.getMsg() : messageFactory.getInstance(e.getCode()).getMsg();
                        resMap.put("dataId", dataId);
                        resMap.put("errMsg", msg);
                        log.info("批量生成客户号异常:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
                    } catch (Exception e) {
                        resMap.put("dataId", dataId);
                        resMap.put("errMsg", e.getMessage());
                        log.info("批量生成客户号异常:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
                    } finally {
                        resMap.put("requestNo", requestNo);
                        resList.add(resMap);
                    }
                }
            }
            countDownLatch.countDown();
        }
    }

    class RunThread implements Runnable {

        private List<BatchCustomerRo> list;
        private int startIndex;
        private int endIndex;
        private CountDownLatch countDownLatch;
        private List<Map<String, Object>> resList;
        private String systemSign;
        private String subSystemSign;
        private String signature;
        private Long requestTimestamp;

        RunThread(List<BatchCustomerRo> ros, int startIndex, int endIndex,
                  CountDownLatch countDownLatch, List<Map<String, Object>> resList,
                  String systemSign, String subSystemSign,
                  String signature, Long requestTimestamp) {
            this.list = ros;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.countDownLatch = countDownLatch;
            this.resList = resList;
            this.systemSign = systemSign;
            this.subSystemSign = subSystemSign;
            this.signature = signature;
            this.requestTimestamp = requestTimestamp;
        }

        @Override
        public void run() {
            List<BatchCustomerRo> subList = list.subList(startIndex, endIndex);
            //TODO 逻辑处理
            for (BatchCustomerRo ro : subList) {
                Map<String, Object> resMap = new HashMap<>(8);
                String dataId = ro.getDataId();
                String requestNo = ro.getRequestNo();
                if (StringUtils.isBlank(dataId)) {
                    resMap.put("dataId", null);
                    resMap.put("requestNo", requestNo);
                    resMap.put("errMsg", "dataId不能为空");
                    resList.add(resMap);
                } else {
                    BaseRequest<CustomerInfoRo> singleRequest = new BaseRequest<>();
                    singleRequest.setRequestTimestamp(requestTimestamp);
                    singleRequest.setSystemSign(systemSign);
                    singleRequest.setSubSystemSign(subSystemSign);
                    singleRequest.setSignature(signature);
                    singleRequest.setBody(ro);
                    try {
                        Map<String, String> singleResMap;
                        singleResMap = baseCustomerService.createCustomerNo(singleRequest);
                        resMap.put("dataId", dataId);
                        resMap.put("customerNo", singleResMap.get("customerNo"));
                    } catch (CustomerException e) {
                        String msg = StringUtils.isNotBlank(e.getMsg()) ? e.getMsg() : messageFactory.getInstance(e.getCode()).getMsg();
                        resMap.put("dataId", dataId);
                        resMap.put("errMsg", msg);
                        log.info("批量生成客户号异常:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
                    } catch (Exception e) {
                        resMap.put("dataId", dataId);
                        resMap.put("errMsg", e.getMessage());
                        log.info("批量生成客户号异常:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
                    } finally {
                        resMap.put("requestNo", requestNo);
                        resList.add(resMap);
                    }
                }
            }
            countDownLatch.countDown();
        }
    }

}